package com.loie.datacenter.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.loie.datacenter.model.stockpo.Bar;
import com.loie.datacenter.model.stockpo.Dayclose;
import com.loie.datacenter.model.stockpo.MaxDrawdownResult;
import com.loie.datacenter.model.stockpo.TradeLog;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Data
public class GridTradingBacktest {
    private static final Logger logapp = LoggerFactory.getLogger("applog");
    private List<Bar> bars = new ArrayList<>();
    private List<TradeLog> tradeLogs = new ArrayList<>();
    public double basePrice;
    private int position = 0;
    private double firstcash = 0;
    private double cash = 0;  // 初始资金10万
    private  double gridStep = 0.05;  // 3%网格间距[历史对话]()
    private  double downgridStep = 0.05;
    private  int lotSize = 500;       // 每笔交易100股
    private int firstsize = 2500;
    private String stockCode;
    private String stockName;
    private Double finalValue;
    private Double finalprofit;
    private Double finalprofitrate;
    private Double firstprice=0.0;
    private Double maxprice=0.0;
    private Double minprice=0.0;
    private Double curprice=0.0;
    private Integer buycount=0;
    private Integer sellcount=0;
    private double annualVolatility=0;
    private MaxDrawdownResult maxDrawdownResult=new MaxDrawdownResult();



    public void loadData(String filePath) throws Exception {
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            while ((line = br.readLine()) != null) {
                String[] parts = line.split(",");
                String timestamp = parts[1];
                if (timestamp.equals("time")) continue;
                String trimmed = timestamp.substring(0, 12); // 得到202501020935000
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
                LocalDateTime dt = LocalDateTime.parse(trimmed, formatter);

                Bar bar = new Bar(dt,
                        Double.parseDouble(parts[3]),
                        Double.parseDouble(parts[4]),
                        Double.parseDouble(parts[5]),
                        Double.parseDouble(parts[6]));
                bars.add(bar);
            }
        }
        cash = firstcash;
        basePrice = bars.get(0).getClose();
        //basePrice =3.49;
        //position=+firstsize;// 初始基准价为第一根K线收盘价
        //cash=cash-position*basePrice;
        executeTrade(bars.get(0).getTimestamp(), "BUY", basePrice, firstsize, 0);
    }

    public Boolean loadsingletxtData(String filePath,double firstcash1,int  firstsize1,double gridStep1,double downgridStep1) throws Exception {
        try (   //
        FileInputStream fis = new FileInputStream(filePath);
        // 创建 InputStreamReader 并指定编码为 GBK
        InputStreamReader isr = new InputStreamReader(fis, "GBK");
        // 创建 BufferedReader 用于按行读取文件内容
        BufferedReader br = new BufferedReader(isr)){
            // 跳过标题行
            //br.readLine();

            String line;
            int lineNumber = 0;
            List<Dayclose> daycloseList = new ArrayList<>();
            while ((line = br.readLine()) != null) {
                lineNumber++;

                // 处理第一行：获取股票代码和名称
                if (lineNumber == 1) {
                    String[] headerParts = line.trim().split("\\s+");
                    if (headerParts.length >= 2) {
                        stockCode = headerParts[0];
                        stockName = headerParts[0];
                        continue;
                    }
                }
                    // 分割字段（处理任意空白字符）
                    if (lineNumber<3) continue;
                    String[] parts = line.trim().split("\\s+");
                    String time = parts[0];
                    if (time.contains("通达信")) continue;
                    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd-HH:mm");
                    LocalDateTime dateTime = LocalDateTime.parse(time.trim(), inputFormatter);

                    // 转换为目标格式
                    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
                    String timestamp = dateTime.format(outputFormatter);
                    LocalDateTime dt = LocalDateTime.parse(timestamp, outputFormatter);
                    //System.out.println(dt);


                    double open = Double.parseDouble(parts[1]);
                    double high = Double.parseDouble(parts[2]);
                    double low = Double.parseDouble(parts[2]);
                    double close = Double.parseDouble(parts[4]);

                Bar bar = new Bar(dt,
                        open,
                        high,
                        low,
                        close);
                bars.add(bar);

            }
            //System.out.println(bars);
                if (firstcash1 > 0)
                    firstcash = firstcash1;
                else
                    firstcash = 30000;
                if (firstsize1>0)
                    firstsize=firstsize1;
                else
                    firstsize=2500;
                if (gridStep1>0)
                    gridStep=gridStep1/100;
                if(downgridStep1>0)
                    downgridStep=downgridStep1/100;
            //System.out.println("gridStep"+gridStep);
            //System.out.println("downgridStep"+downgridStep);
                cash=firstcash;
                basePrice = bars.get(0).getClose();
//                if (basePrice>20){
//                    log.info(String.format("股票代码:%s-名称：%s,初始股价:%.2f已超20元，暂不考虑",stockCode,stockName,basePrice));
//                    return false;
//                }
                firstprice=basePrice;
                if (maxprice<bars.get(0).getHigh()&&bars.get(0).getHigh()>0 )maxprice=bars.get(0).getHigh();
                if ((minprice>bars.get(0).getLow()&&bars.get(0).getLow()>0)||minprice==0)minprice=bars.get(0).getLow();
                //basePrice =3.49;
                //position=+firstsize;// 初始基准价为第一根K线收盘价
                if (cash < firstsize * basePrice) {
                    log.info(String.format("股票代码:%s-名称：%s,初始股价:%.2f,初始资金:%.2f不足",
                            stockCode,stockName,firstprice,cash));
                    return false;

                } else {
                    //System.out.println(daycloseList);
                    //logapp.info(bars.toString());
                    executeTrade(bars.get(0).getTimestamp(), "BUY", basePrice, firstsize, 0);
                    return true;
                }

            }

    }

    public Boolean loadtxtData(String filePath,double firstcash1,int  firstsize1,double gridStep1,double downgridStep1,String timer2,int lotsize1) throws Exception {
        try (

                //BufferedReader br = new BufferedReader(new FileReader(filePath)))
                //
                FileInputStream fis = new FileInputStream(filePath);
                // 创建 InputStreamReader 并指定编码为 GBK
                InputStreamReader isr = new InputStreamReader(fis, "GBK");
                // 创建 BufferedReader 用于按行读取文件内容
                BufferedReader br = new BufferedReader(isr)) {
            // 跳过标题行
            //br.readLine();

            String line;
            int lineNumber = 0;
            List<Dayclose>daycloseList=new ArrayList<>();
            while ((line = br.readLine()) != null) {
                lineNumber++;

                // 处理第一行：获取股票代码和名称
                if (lineNumber == 1) {
                    String[] headerParts = line.trim().split("\\s+");
                    if (headerParts.length  >= 2) {
                        stockCode = headerParts[0];
                        stockName = headerParts[1];
                        continue;
                    }
                }
                // 分割字段（处理任意空白字符）
                if (lineNumber<3) continue;
                String[] parts = line.trim().split("\\s+");
                //System.out.println(parts);

                // 验证数据完整性
                if (parts.length < 8) {
                    System.err.println(" 无效数据行: " + line);
                    continue;
                }
//                DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
//                LocalDate date = LocalDate.parse(parts[0], dateFormatter);

                String time = parts[0] + " " + parts[1];
                DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HHmm");
//                DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
                LocalDateTime dateTime = LocalDateTime.parse(time.trim(), inputFormatter);
                if (!Strings.isEmpty(timer2)) {
                    LocalDateTime dateTime2;
                    try {
                        dateTime2 = LocalDateTime.parse(timer2.trim(), inputFormatter);
                        if (dateTime.isBefore(dateTime2)) {
                            //System.out.println("历史数据时间:"+dateTime+"小于限定的时间"+dateTime2);
                            continue;
                        }
                    } catch (DateTimeParseException e) {
                        System.out.println(" 时间2格式错误，请检查是否为yyyy/MM/dd HHmm格式");


                    }
                }

                // 转换为目标格式
                DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
                String timestamp = dateTime.format(outputFormatter);


                LocalDateTime dt = LocalDateTime.parse(timestamp, outputFormatter);
                //System.out.println(dt);


                double open = Double.parseDouble(parts[2]);
                double high = Double.parseDouble(parts[3]);
                double low = Double.parseDouble(parts[4]);
                double close = Double.parseDouble(parts[5]);
                if (parts[1].equals("1500")){
                    Dayclose dayclose=new Dayclose();
                    dayclose.setDatestr(parts[0]);
                    dayclose.setClose(close);
                    daycloseList.add(dayclose);

                }
                Bar bar = new Bar(dt,
                        open,
                        high,
                        low,
                        close);
                bars.add(bar);

            }
            log.info(daycloseList.toString());
            double[] logReturns = new double[daycloseList.size() - 1];
            for (int i=1;i<daycloseList.size();i++){
                logReturns[i-1] = Math.log(daycloseList.get(i).getClose()) - Math.log(daycloseList.get(i-1).getClose());
            }
            log.info(logReturns.toString());
            double mean = calculateMean(logReturns);
            //log.info("mean:"+mean);

            double stdDev = calculateStdDev(logReturns, mean);


            // 计算波动率
            annualVolatility = stdDev * Math.sqrt(250);
            System.out.println(String.format("mean=%f,stdDev=%f,annualVolatility=%f",mean,stdDev,annualVolatility));
            if (firstcash1 > 0)
                firstcash = firstcash1;
            else
                firstcash = 30000;

            if (firstsize1>0)
                firstsize=firstsize1;
            else
                firstsize=2500;
            if (lotsize1>500)
                lotSize=lotsize1;
            if (gridStep1>0)
                gridStep=gridStep1/100;
            if(downgridStep1>0)
                downgridStep=downgridStep1/100;
            cash=firstcash;
            basePrice = bars.get(0).getClose();
            if (basePrice>30){
                log.info(String.format("股票代码:%s-名称：%s,初始股价:%.2f已超30元，暂不考虑",stockCode,stockName,basePrice));
                return false;
            }
            firstprice=basePrice;
            if (maxprice<bars.get(0).getHigh()&&bars.get(0).getHigh()>0 )maxprice=bars.get(0).getHigh();
            if ((minprice>bars.get(0).getLow()&&bars.get(0).getLow()>0)||minprice==0)minprice=bars.get(0).getLow();
            //basePrice =3.49;
            //position=+firstsize;// 初始基准价为第一根K线收盘价
            if (cash < firstsize * basePrice) {
                log.info(String.format("股票代码:%s-名称：%s,初始股价:%.2f,初始资金:%.2f不足",
                        stockCode,stockName,firstprice,cash));
                return false;

            } else {
                System.out.println(daycloseList);
                executeTrade(bars.get(0).getTimestamp(), "BUY", basePrice, firstsize, 0);
                return true;
            }

        }


    }

    public Boolean loadjsonData(List<JSONObject> results, double firstcash) throws Exception {
        for (int i = 0; i < results.size(); i++) {
            JSONObject json = results.get(i);
            //System.out.println(json.getString("timestamp").trim());
            DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd-HH:mm");
            LocalDateTime dateTime = LocalDateTime.parse(json.getString("timestamp").trim(), inputFormatter);

            // 转换为目标格式
            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
            String timestamp = dateTime.format(outputFormatter);


            LocalDateTime dt = LocalDateTime.parse(timestamp, outputFormatter);

            Bar bar = new Bar(dt,
                    json.getDouble("open"),
                    json.getDouble("high"),
                    json.getDouble("low"),
                    json.getDouble("close"));
            bars.add(bar);

        }
        if (firstcash > 0)
            cash = firstcash;
        else
            cash = 30000;
        basePrice = bars.get(0).getClose();
        //basePrice =3.49;
        //position=+firstsize;// 初始基准价为第一根K线收盘价
        if (cash < firstsize * basePrice) {
            System.out.println("初始资金" + String.valueOf(cash) + "不足");
            return false;

        } else {
            executeTrade(bars.get(0).getTimestamp(), "BUY", basePrice, firstsize, 0);
            return true;
        }
    }

    public void executeStrategy() {
        //double[] logReturns = new double[bars.size() - 1];
        //Integer i=0;
        maxDrawdownResult.setMaxPrice(bars.get(0).getClose());
        maxDrawdownResult.setMaxIndex(0);
        maxDrawdownResult.setMaxDrawdownPercent(0.0);
        maxDrawdownResult.setMaxDrawdown(0.0);
        maxDrawdownResult.setPeakIndex(0);
        maxDrawdownResult.setTroughIndex(0);
        for (int i=1;i< bars.size();i++) {

            Bar bar=bars.get(i);
            double maxprice1=bar.getHigh();
            double minprice1=bar.getLow();

            //寻找最大回撤
            if (bar.getClose()>maxDrawdownResult.getMaxPrice()){
                maxDrawdownResult.setMaxPrice(bar.getClose());
                maxDrawdownResult.setMaxIndex(i);
            }
            else
            {
                double drawdown =maxDrawdownResult.getMaxPrice() - bar.getClose();
                if (drawdown> maxDrawdownResult.getMaxDrawdown()) {
                    maxDrawdownResult.setMaxDrawdown(drawdown);
                    maxDrawdownResult.setMaxPricetime(bars.get(maxDrawdownResult.getMaxIndex()).getTimestamp());
                    maxDrawdownResult.setPeakIndex(maxDrawdownResult.getMaxIndex());
                    maxDrawdownResult.setPeakPrice(maxDrawdownResult.getMaxPrice());
                    maxDrawdownResult.setTroughPrice(bar.getClose());
                    maxDrawdownResult.setTroughPricePricetime(bar.getTimestamp());

                    maxDrawdownResult.setMaxDrawdownPercent(drawdown/maxDrawdownResult.getMaxPrice());

                    maxDrawdownResult.setTroughIndex(i);
                }
            }

            double currentPrice=0.0;
            //double currentPrice = bar.getClose();
            //double deviation = (currentPrice - basePrice) / basePrice;
            double deviation =0.0;
            // 触发卖出条件[5]()

            //logReturns[i-1] = Math.log(bars.get(i).getClose()) - Math.log(bars.get(i-1).getClose());
            if (maxprice1>basePrice) {
                deviation = (maxprice1 - basePrice) / basePrice;

                if (deviation >= gridStep && position >= lotSize) {


                    Boolean match = bar.getTimestamp().getHour() == 9
                            && bar.getTimestamp().getMinute() == 30;
//                basePrice = currentPrice;  // 更新基准价
                    if (!match)
                        currentPrice = Double.valueOf(String.format("%.2f", basePrice * (1 + gridStep)));
                    else
                        currentPrice = maxprice1;
                    executeTrade(bar.getTimestamp(), "SELL", currentPrice, lotSize, basePrice);

                    basePrice = currentPrice;

                }
            }
            // 触发买入条件
            else if  (minprice1<basePrice){
                deviation=(minprice1 - basePrice) / basePrice;
                if (deviation <= -downgridStep && cash >= minprice1 * lotSize) {
                    Boolean match = bar.getTimestamp().getHour() == 9
                            && bar.getTimestamp().getMinute() == 30;
                    if (!match)
                        currentPrice = Double.valueOf(String.format("%.2f", basePrice * (1 - downgridStep)));
                    else
                        currentPrice=minprice1;
                    executeTrade(bar.getTimestamp(), "BUY", currentPrice, lotSize, basePrice);
//                basePrice = currentPrice;
                    basePrice = currentPrice;

                }
            }
            if (maxprice<bar.getHigh()&&bar.getHigh()>0 )maxprice=bar.getHigh();
            if ((minprice>bar.getLow()&&bars.get(0).getLow()>0)||minprice==0)minprice=bar.getLow();
        }
        //if (maxDrawdownResult.getPeakIndex()>0)
            //maxDrawdownResult.setMaxDrawdownPercent(maxDrawdownResult.getMaxDrawdown()/bars.get(maxDrawdownResult);

        if (bars.size()>0) curprice=bars.get(bars.size()-1).getClose();
        //log.info(logReturns.toString());
        //double mean = calculateMean(logReturns);

        //double stdDev = calculateStdDev(logReturns, mean);
       // System.out.println(String.format("mean=%f,stdDev=%f",mean,stdDev));

        // 计算波动率
         //annualVolatility = stdDev / mean * Math.sqrt(250);
    }

    private void executeTrade(LocalDateTime time, String type, double price, int qty, double baseprice) {
        // 计算手续费（万2.5佣金）[5]()
        double commission = price * qty * 0.00025;
        if (commission < 5) commission = 5;
        if (type.equals("BUY")) {
            cash -= (price * qty + commission);
            position += qty;
        } else {
            cash += (price * qty - commission);
            position -= qty;
        }
        tradeLogs.add(new TradeLog(time, type, price, qty, position, position * price, cash, baseprice,firstcash));
    }

    public void generateReport() {
         finalValue = cash + position * bars.get(bars.size() - 1).getClose();
        System.out.println("========  回测结果 ========");
        //double firstvalue=50000;
        finalprofit=finalValue-firstcash;
        finalprofitrate=(finalValue / firstcash - 1) * 100;
        log.info(String.format("股票代码:%s-名称：%s", stockCode,stockName));
        log.info(String.format(" 初始资金: %.2f\n", firstcash));
        log.info(String.format(" 最终资产: %.2f,其中股票:%.2f,现金%.2f,总收益: %.2f,总收益率: %.2f", finalValue,
                position * bars.get(bars.size() - 1).getClose(), cash,finalprofit,finalprofitrate));

        //System.out.printf(" 总收益率: %.2f\n",finalprofitrate );
        //Integer buycount = 0;
        //Integer sellcount = 0;
        double maxcash = 0;

        for (int i = 0; i <= tradeLogs.size() - 1; i++) {
            //logReturns[i-1] = Math.log(tradeLogs.get(i).get) - Math.log(endPrices[i-1]);
            if (tradeLogs.get(i).getType().equals("SELL")) {
               // log.info("卖：" + JSON.toJSONString(tradeLogs.get(i)));

                sellcount++;


            } else if (tradeLogs.get(i).getType().equals("BUY")) {
               // log.info("买：" + JSON.toJSONString(tradeLogs.get(i)));
                buycount++;
            }
            if (firstcash - tradeLogs.get(i).getCash() > maxcash)
                maxcash = firstcash - tradeLogs.get(i).getCash();
        }
        log.info(String.format(" 交易次数: " + tradeLogs.size() + "，其中买入%d,卖出%d,最大现金%.2f",
                buycount, sellcount, maxcash));
        //System.out.println(tradeLogs);
        String json = JSON.toJSONString(tradeLogs);
        //System.out.println(json.toString());

    }
    private  double calculateMean(double[] data) {
        double sum = 0;
        for (double num : data) {
            sum += num;
        }
        return sum / data.length;
    }
    private  double calculateStdDev(double[] data, double mean) {
        double sum = 0;
        for (double num : data) {
            sum += Math.pow(num - mean, 2);
        }
        return Math.sqrt(sum / (data.length - 1));
    }

    public static void main(String[] args) throws Exception {
        GridTradingBacktest engine = new GridTradingBacktest();
        String filename = "D:\\history_300591.csv";
        engine.loadData(filename);
        System.out.println(engine.basePrice);
        //engine.basePrice=engine.bars.get(0).close;
        // System.out.println(engine.bars);
//        for (Bar bar:engine.bars){
//            System.out.println(bar.getTimestamp()+"/"+bar.getClose());
//        }
        engine.executeStrategy();
        engine.generateReport();
    }

}
